package com.kim.zull.server.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kim.common.utilcom.constants.CodeEnum;
import com.kim.common.utilcom.model.Result;
import com.kim.oauth.common.constants.Oauth2ExceptionEnum;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.*;

/**
 * 拦截防止xss注入
 * 带sql注入拦截 (旧版本)
 */
@Component
@Slf4j
@RefreshScope
@Deprecated
public class XssFilter extends ZuulFilter {

    /**
     * springmvc启动时自动装配json处理类
     */
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 10;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String contentType = request.getContentType();
        if (StringUtils.isBlank(contentType)) {
            return null;
        } else if (StringUtils.equals(contentType, "application/x-www-form-urlencoded")
                || StringUtils.equals(contentType, "application/x-www-form-urlencoded;charset=UTF-8")) {
            Map<String, String[]> parameterMap = request.getParameterMap();
            Iterator it_d = parameterMap.entrySet().iterator();
            while (it_d.hasNext()) {
                Map.Entry<String, String[]> entry_d = (Map.Entry) it_d.next();
                String key = entry_d.getKey();
                String[] value = entry_d.getValue();
                if (value != null) {
                    List<String> strings = Arrays.asList(value);
                    for (int i = 0; i < strings.size(); i++) {
                        strings.set(i, StringEscapeUtils.escapeHtml(strings.get(i)));
                        strings.set(i, StringEscapeUtils.escapeJavaScript(strings.get(i)));
                    }
                }
                parameterMap.put(key, value);
            }
            String newBody = JSON.toJSONString(parameterMap);
            //	如果存在sql注入,直接拦截请求
            if (newBody.contains("forbid")) {
                setUnauthorizedResponse(requestContext);
            }
            final byte[] reqBodyBytes = newBody.getBytes();
            requestContext.setRequest(new HttpServletRequestWrapper(request) {

                @Override
                public ServletInputStream getInputStream() {
                    return new ServletInputStreamWrapper(reqBodyBytes);
                }

                @Override
                public int getContentLength() {
                    return reqBodyBytes.length;
                }

                @Override
                public long getContentLengthLong() {
                    return reqBodyBytes.length;
                }
            });

        } else if (StringUtils.equals(contentType, "application/json")
                || StringUtils.equals(contentType, "application/json;charset=UTF-8")) {
            try {
                InputStream in = requestContext.getRequest().getInputStream();
                String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
                Map<String, Object> parameterMap = cleanXSS(body);

                String newBody = JSON.toJSONString(parameterMap);
                //	如果存在sql注入,直接拦截请求
                if (newBody.contains("forAlone")) {
                    setUnauthorizedResponse(requestContext);
                }
                final byte[] reqBodyBytes = newBody.getBytes();
                requestContext.setRequest(new HttpServletRequestWrapper(request) {

                    @Override
                    public ServletInputStream getInputStream() {
                        return new ServletInputStreamWrapper(reqBodyBytes);
                    }

                    @Override
                    public int getContentLength() {
                        return reqBodyBytes.length;
                    }

                    @Override
                    public long getContentLengthLong() {
                        return reqBodyBytes.length;
                    }
                });
            } catch (IOException e) {
                log.error("xss过滤器读取参数异常", e);
            }
        }
        try {
            String s = StreamUtils.copyToString(requestContext.getRequest().getInputStream(), Charset.forName("UTF-8"));
            System.out.println(s);
        } catch (IOException e) {
            log.error("xss过滤器读取参数异常", e);
        }
        return null;
    }

    private Map<String, Object> cleanXSS(String value) {
        value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
        value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
        value = value.replaceAll("'", "& #39;");
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("script", "");
        value = value.replaceAll("[*]", "[" + "*]");
        value = value.replaceAll("[+]", "[" + "+]");
        value = value.replaceAll("[?]", "[" + "?]");

        String badStr = "'|and|exec|execute|insert|select|delete|update|count|drop|%|chr|mid|master|truncate|" +
                "char|declare|sitename|net user|xp_cmdshell|;|or|+|,|like'|and|exec|execute|insert|create|drop|" +
                "table|from|grant|use|group_concat|column_name|" +
                "information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|" +
                "chr|mid|master|truncate|char|declare|or|;|--|,|like|//|/|%|#";

        JSONObject json = JSON.parseObject(value);
        String[] badStrs = badStr.split("\\|");
        Map<String, Object> map = json;
        Map<String, Object> mapJson = new HashMap<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String value1 = entry.getValue().toString();
            for (String bad : badStrs) {
                if (value1.equalsIgnoreCase(bad)) {
                    value1 = "forAlone";
                    mapJson.put(entry.getKey(), value1);
                    break;
                } else {
                    mapJson.put(entry.getKey(), entry.getValue());
                }
            }
        }
        return mapJson;
    }

    /**
     * 设置500拦截状态
     */
    private void setUnauthorizedResponse(RequestContext requestContext) {
        HttpServletResponse response = requestContext.getResponse();
        Result result = Result.failed(CodeEnum.XSS.getRetCode(),CodeEnum.XSS.getRetMsg());
        try {
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(result));
            response.getWriter().flush();
            response.getWriter().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
